<?php
namespace Pay\Controller;


class PayController extends CommonController {

    public function Index(){
        $this->Main();
    }

    /**
     * 首页
     */
    public function Main(){
        $pay_method = C('PAY_METHOD');
        $method = I('get.method');
        $hash   = form_hash();
        $this->assign('pay_method', in_array($method, $pay_method) ? $method : $pay_method[0]);
        $this->assign('hash', $hash);
        $sso_server = C('SSO_SERVER');

        //检测是否已经登陆
        $user = $this->user;
        if($user->user_id > 0){
            $userinfo['user_id']    = $user->user_id;
            $userinfo['user_name']  = $user->user_name;
            $userinfo['user_money'] = $user->user_money;
            $userinfo['user_cash']  = 0;
            $this->assign('user', $userinfo);
        }else{
            $ref = ref_url();
            $C_Q = 'ref';
            $C_URL = $ref;
            $C_SSOLoginOP = urlencode( 'http://' . $_SERVER['SERVER_NAME'] . U('User/Notice/') );
            $this->assign('login_url', "$sso_server/login.aspx?C_Q=$C_Q&C_URL=$C_URL&C_SSOLoginOP=$C_SSOLoginOP&op=Notice&C_SSOPlatform_Code=".C('PLATFORM_ID'));
            $this->assign('reg_url', "$sso_server/register.aspx?C_Q=$C_Q&C_URL=$C_URL&C_SSOLoginOP=$C_SSOLoginOP&op=Notice");
        }
        $this->display('index');
    }

    /**
     * 验证手机验证码/支付密码页面
     */
    public function checkCode(){
        $this->display('Public/pay_layer');
    }

    /**
     * 下单页面
     */
    public function Order(){
        //检查登录
        $this->chk_login();
        if( IS_POST ){
            //数据
            $post = I('post.');

            compare_form_hash($post['hash']);  //防止重复提交

            $method = $post['pay_method'];
            $gid    = (int)$post['gid'];
            $sid    = (int)$post['sid'];
            $is_alipay = strtolower($method) === 'alipay' ? true : false;  // 是否支付宝支付
            $charge_to = $post['charge_to'];

            //如果是通币充值，需要进行安全验证
            if( ! $is_alipay && ! $this->_chkSecurity() ){
                $this->error('非法操作');
            }else{
                //如果是支付宝支付，则检测充值到哪里
                $chk_arr = array('game', 'tb');
                if( ! in_array($charge_to, $chk_arr) ) $this->error('非法操作');
                unset($chk_arr);
            }
            $order_amount = floatval($post['order_amount']) > 0 ? floatval($post['order_amount']) : 0;
            //处理用户输入的金额
            if( $post['order_amount'] === 'other' ){
                $order_amount = check_price($post['order_money']) ? $post['order_money'] : 0;
            }
            $db = zyt_data_init();
            /** ↓↓↓↓↓↓↓ 表单错误校验 ↓↓↓↓↓↓↓ */
            if( empty($method) || ! in_array($method, C('PAY_METHOD')) ){
                $this->error('支付方式错误');
            }
            if($charge_to === 'game'){
                /* 此处校验 game_id 与 server_id 是否对应 */
                $server = $db->getGameServerInfo($sid)[0];
                if($server['game_id'] != $gid){
                    $gid = 0;
                    $sid = 0;
                }
                if( $gid <= 0 || $sid <= 0 ){
                    $this->error('未选择充入游戏或服务器');
                }
            }
            if( $order_amount <= 0 ){
                $this->error('提交订单数据有误');
            }
            
            /*用户充值通币，游乐淘账号的通币减少，当游乐淘账号的通币余额为0时，用户不能充值通币，提示“系统维护中，暂不能充值通币”，
              当游乐淘账号的通币余额<用户的充值金额时，提示“你充值的金额太大，请修改充值金额为小于【游乐淘账号的通币余额】后再充值，谢谢！“ */
            if( $method === 'alipay' ){
                // 1. >>> 获取游乐淘平台账户通余额
                $platformUser = $this->getPlatformUserInfo();
                $platTB   = $platformUser['tb'];
                // 2. >>> 验证可充值通币
                if( $platTB == 0 ){
                    $this->error('系统维护中，暂不能充值通币');
                }elseif( $platTB < $order_amount ){
                    $this->error('你充值的金额太大，请修改充值金额为小于'.$platTB.'后再充值，谢谢！');
                }
            }

            /** ↑↑↑↑↑↑↑ 表单错误校验 ↑↑↑↑↑↑↑ */
            //订单处理
            if( $charge_to === 'game' ){
                //获取游戏信息
                $game   = $db->getGameInfo($gid)[0];
                //开始执行支付
                $order_sn = generate_order_sn();   //生成订单号
                $subject  = '云通游戏【' . $game['game_name'] . '】充值_' . $order_sn;
                $body     = '云通游戏【' . $game['game_name'] . '】充值_' . $order_amount . '元';
                //信息写入SESSION，用于回调
                session('pay_info', array(
                    'game_id'   => $gid,
                    'server_id' => $sid,
                    'uid'       => $this->user['user_id'],
                ));
            }else{
                $order_sn = generate_order_sn();   //生成订单号
                $subject  = '通币充值_' . $order_sn;
                $body     = '通币充值_' . $order_amount . '元';
                session('pay_info', array(
                    'charge_to' => $charge_to,
                    'uid'       => $this->user['user_id'],
                ));
            }

            $M = D('Order');
            $addOrder = $M->addOrder($order_sn, $this->user['user_id'], $order_amount, $charge_to, $method, 0, $subject, session('pay_info')['server_id'], session('pay_info')['game_id']);
            if( ! $addOrder ) $this->error('订单生成失败， 请重新下订单', U('Pay/Main'));

            if( $method == 'alipay' ){
                $this->_alipay($order_sn, $subject, $order_amount, $body, session('pay_info'));
            }elseif( $method == 'tb' ){
                $this->_tbpay($order_sn, $subject, $order_amount, $body);
            }
        }
    }

    /**
     * 通币异动时，交易安全验证
     */
    private function _chkSecurity(){
        $pass = false;
        if( I('post.charge_to') !== 'game' ) return $pass;   //使用通币充值，只能充值到游戏，所以charge_to 必须是'game'
        $security = session('SECURITY_PASS');
        if( ! $security ) return $pass;

        $mobile = $this->user['user_phone'];
        $uid    = $this->user['user_id'];

        $db = zyt_data_init();
        //获取支付密码
        $data = $db->table('User')->field('user_paypassword')->where("user_id = $uid")->find();
        $pay_pass = $data['user_paypassword'];

        //获取验证码
        $data = $db->table('send_code')->field('code_number')->where("code_bind_number = '$mobile'")->find();
        $sms_code = $data['code_number'];

        //生成校验码
        $result = md5($pay_pass . $sms_code);

        if( $security === $result ){
            $pass = true;
        }

        //删除该用户验证码
        $mobile = $this->user['user_phone'];
        $db->table('send_code')->where("code_bind_number = '$mobile'")->delete();
        //删除安全验证SESSION
        session('SECURITY_PASS', null);
        return $pass;
    }

    /**
     * 通币 & 余额支付
     *
     * @param $order_sn
     * @param $subject
     * @param $order_amount
     */
    private function _tbpay($order_sn, $subject, $order_amount, $body){
        $post = I('post.');
        $charge_type = $post['charge_type'];
        $gid = $post['gid'];
        $sid = $post['sid'];
        $uid = $this->user['user_id'];
        $order_amount = floatval($order_amount);

        $db = zyt_data_init();
        //查询支付类型是否允许
        $gameinfo = $db->getGameInfo($gid);
        if(empty($gameinfo)){
            //该游戏不存在
            $this->error('该游戏不存在');
        }else {
            $allow_charge_type = $gameinfo[0]['game_recharge_class'];
            $pay_type = C('PAY_TYPE');

            if ($allow_charge_type == 12 && $charge_type != 'tb') {
                //该游戏只支持通币充值
                $this->error('该游戏只支持通币充值');
            }
            //获取用户资金信息
            $user_acc = $db->getUserCapital($uid);
            if (empty($user_acc)) {
                $this->error('该用户不存在');
            }
            $user_acc = $user_acc[0];
            //判断充值类型
            $result = array();
            if ($charge_type == 'tb') {
                //通币充值
                if ($user_acc['tong_money_count'] < $order_amount) {
                    $this->error('用户通币余额不足');
                }
                //扣除通币
                //$result = $db->updateUserTb($uid, -$order_amount);
                $log_type = $pay_type['TB_PAY'];
            } elseif ($charge_type == 'ye') {
                //消费余额充值
                if ($user_acc['consumed_money_count'] < $order_amount) {
                    $this->error('用户消费余额不足');
                }
                //扣除消费余额
                //$result = $db->updateUserMoney($uid, -$order_amount);
                $log_type = $pay_type['YE_PAY'];
            } else {
                $this->error('支付类型不正确');
                $log_type = '';
            }
            $slave = $this->getPlatformUserInfo()['uid'];
            $result = $this->pay_success($order_sn, $uid, $slave, $log_type, $order_amount, $subject, $gid, $sid, 'game', $charge_type);
            $result ? $this->success('支付成功', U('Pay/Main')) : $this->error('支付失败', U('Pay/Main'));
        }
    }

    /**
     * 支付宝支付方法
     *
     * @param $order_sn
     * @param $subject
     * @param $total_fee
     * @param $body
     */
    private function _alipay($order_sn, $subject, $total_fee, $body, $extra = array()){
        vendor('Alipay.Core');
        vendor('Alipay.Submit');
        vendor('Alipay.MD5');
        vendor('Alipay.Notify');

        $alipay_config = C('ALIPAY');
        $parameter = array(
            "service" => "create_direct_pay_by_user",
            "partner" => $alipay_config['PARTNER'],
            "seller_email" => trim($alipay_config['SELLER_MAIL']),
            "payment_type"	=> 1,
            "notify_url"	=> $alipay_config['NOTIFY_URL'],
            "return_url"	=> $alipay_config['RETURN_URL'],
            "out_trade_no"	=> $order_sn,
            "subject"	=> $subject,
            "total_fee"	=> $total_fee,
            "body"	=> $body,
            "show_url"	=> '',
            "anti_phishing_key"	=> '',
            "exter_invoke_ip"	=> get_client_ip(),
            "_input_charset"	=> $alipay_config['CHARSET'],
        );

        //自定义参数
        if( !empty($extra) && is_array($extra) ){
            $parameter['extra_common_param'] = serialize($extra);
        }

        //重构原生支付宝配置信息
        $_config = array(
            'partner' => $alipay_config['PARTNER'],
            'seller_email' => $alipay_config['SELLER_MAIL'],
            'key' => $alipay_config['KEY'],
            'sign_type' => $alipay_config['SIGN_TYPE'],
            'input_charset' => $alipay_config['CHARSET'],
            'cacert' => $alipay_config['CACERT'],
            'transport' => $alipay_config['TRANSPORT'],
        );

        $alipaySubmit = new \AlipaySubmit($_config);
        $html_text = $alipaySubmit->buildRequestForm($parameter,"get", "");
        echo $html_text;
    }

    /**
     * 支付通知回调处理
     */
    public function Notify_url(){
        //验证成功
        $result = 0;
        if( $_POST['trade_status'] === 'TRADE_FINISHED' || $_POST['trade_status'] === 'TRADE_SUCCESS' ){
            $extra_common_param = urldecode($_POST['extra_common_param']);
            $pay_info = unserialize($extra_common_param);

            //增加资金记录
            $order_sn = $_POST['out_trade_no'];
            $pay_type = C('PAY_TYPE');
            $log_type = $pay_info['charge_to'] === 'tb' ? $pay_type['CASH_TB'] : $pay_type['CASH_PAY'];
            $slave  = $this->getPlatformUserInfo()['uid'];
            $master = $pay_info['uid'];
            $amount   = $_POST['total_fee'];
            $subject  = $_POST['subject'];
            $game_id  = $pay_info['game_id'];
            $server_id = $pay_info['server_id'];
            $charge_to = $pay_info['charge_to'];
            $result = $this->pay_success($order_sn, $master, $slave, $log_type, $amount, $subject, $game_id, $server_id, $charge_to, 'alipay');
        }
        echo $result ? 'success' : 'fail';

    }

    public function Return_url(){
        $get = I('get.');
        if( $get['is_success'] === 'T' ){
            $this->success('支付成功', U('Pay/Main'));
        }else{
            $this->error('支付失败', U('Pay/Main'));
        }
    }

    //支付成功后处理订单
    private function pay_success($order_sn, $master, $slave, $log_type, $amount, $subject, $game_id, $server_id, $charge_to, $pay_method){

        //这里需要检测订单是否已被处理
        $M = D('Order');
        $map['sn'] = $order_sn;
        $data = $M->where($map)->field('status')->find();
        if( $data['status'] == 1 ){
            return true;
        }

        $platformID = C('PLATFORM_ID');
        $currency   = C('CURRENCY');
        $rmb        = $currency['RMB'];
        $tb         = $currency['TB'];
        $ye         = $currency['YE'];
        $order_time = time();

        $db = zyt_data_init();
        //获取主体与客体目前的通币信息
        $master_user = $db->getUserCapital($master)[0];
        $slave_user  = $db->getUserCapital($slave)[0];

        $master_pre_tb = $master_user['tong_money_count'];
        $master_pre_ye = $master_user['consumed_money_count'];
        $slave_pre_tb  = $slave_user['tong_money_count'];
        $slave_pre_ye  = $slave_user['consumed_money_count'];

        if( $charge_to === 'tb' ){
            //充值到通币
            //对用户账号充值通币
            $db->startTrans();
            $db->updateUserTb($master, $amount);      //给用户增加通币
            $db->updateUserTb($slave, -$amount);     //扣除发行账号的通币

            //添加流水记录
            //第一条：交易主体通币交易记录
            $this->addCapitalLog($order_sn, $master, $slave, $platformID, $log_type, $tb, $amount, $master_pre_tb, $order_time, $subject, $server_id, $game_id);
            //第二条：交易主体的现金交易记录
            $this->addCapitalLog($order_sn, $master, $slave, $platformID, $log_type, $rmb, -$amount, 0, $order_time, $subject);
            //第三条：交易客体通币交易记录
            $this->addCapitalLog($order_sn, $slave, $master, $platformID, $log_type, $tb, -$amount, $slave_pre_tb, $order_time, $subject);
            //第四条：交易客体现金交易记录
            $this->addCapitalLog($order_sn, $slave, $master, $platformID, $log_type, $rmb, $amount, 0, $order_time, $subject);
            $result = $db->commit();
        }else{
            //充值到游戏
            //获取游戏接入的用户ID
            $game = $db->table('game')->field('game_name')->where("game_id = $game_id")->find();
            $game_name = $game['game_name'];
            $gameQ = $db->table('platform_info')->field('user_id')->where("platform_name = '$game_name'")->find();
            $game_uid  = $gameQ['user_id'];

            //获取游戏经营者的资金信息
            $game_user = $db->getUserCapital($game_uid)[0];
            $game_user_pre_tb = $game_user['tong_money_count'];
            $game_user_pre_ye = $game_user['consumed_money_count'];

            switch($pay_method){
                case 'tb':  //通币充值到游戏币
                    $db->startTrans();
                    $db->updateUserTb($master, -$amount);      //扣除用户通币
                    $db->updateUserTb($game_uid, $amount);      //游戏开发者增加通币
                    //添加流水
                    //第一条：买家的通币扣除记录
                    $this->addCapitalLog($order_sn, $master, $game_uid, $platformID, $log_type, $tb, -$amount, $master_pre_tb, $order_time, $subject, $server_id, $game_id);
                    //第二条：游戏经营者获得通币
                    $this->addCapitalLog($order_sn, $game_uid, $master, $platformID, $log_type, $tb, $amount, $game_user_pre_tb, $order_time, $subject);
                    $result = $db->commit();
                    break;
                case 'ye':  //消费余额充值到游戏币
                    $db->startTrans();
                    $master_data['consumed_money_count'] = array('exp', 'consumed_money_count - ' . $amount);
                    $db->table('user_capital')->data($master_data)->where("capital_user_id = '$master'")->save();
                    $slave_data['consumed_money_count'] = array('exp', 'consumed_money_count + ' . $amount);
                    $db->table('user_capital')->data($slave_data)->where("capital_user_id = '$game_uid'")->save();
                    //添加流水
                    //第一条：买家的消费余额扣除记录
                    $this->addCapitalLog($order_sn, $master, $game_uid, $platformID, $log_type, $ye, -$amount, $master_pre_ye, $order_time, $subject, $server_id, $game_id);
                    //第二条：游戏经营者消费余额获得通币
                    $this->addCapitalLog($order_sn, $game_uid, $master, $platformID, $log_type, $ye, $amount, $game_user_pre_ye, $order_time, $subject);
                    $result = $db->commit();
                    break;
                case 'alipay':  //支付宝现金充值到游戏币
                    $db->startTrans();
                    $db->updateUserTb($game_uid, $amount);      //游戏经营者获得通币
                    $db->updateUserTb($slave, -$amount);        //发行账号上减少通币

                    $content = $game_uid . ': ' . $amount . "\n\r";
                    $content .= $slave . ': ' . -$amount . "\n\r";

                    $f = fopen('tb.log', 'w+');
                    fwrite($f, $content);
                    fclose($f);

                    //添加流水
                    //第一条：交易主体现金减少
                    $this->addCapitalLog($order_sn, $master, $slave, $platformID, $log_type, $rmb, -$amount, 0, $order_time, $subject, $server_id, $game_id);
                    //第二条：交易客体现金增加
                    $this->addCapitalLog($order_sn, $slave, $master, $platformID, $log_type, $rmb, $amount, 0, $order_time, $subject);
                    //第三条：游戏经营者通币增加
                    $this->addCapitalLog($order_sn, $game_uid, $slave, $platformID, $log_type, $tb, $amount, $game_user_pre_tb, $order_time, $subject);
                    //第四条：通币发行账号通币减少
                    $this->addCapitalLog($order_sn, $slave, $game_uid, $platformID, $log_type, $tb, -$amount, $slave_pre_tb, $order_time, $subject);
                    $result = $db->commit();
                    break;
                default :
                    $result = 0;
                    break;
            }

            //请求游戏充值SDK
            $sdk_settings = C('GAME_SDK_KIT');
            $gateway      = $sdk_settings['GATEWAY'];
            $key          = $sdk_settings['KEY'];
            import('Org.Net.SDK');
            $sdk = new \Zyt\SDK();
            $sdk->gateway = $gateway;
            $sdk->key     = $key;
            $data = array(
                'uid'      => $master,
                'game_id'  => $game_id,
                'order_sn' => $order_sn,
                'total_fee' => $amount,
            );
            $sdk->start($data);
        }

        //更新订单状态
        $data = array();
        $data['status'] = 1;
        $M->where($map)->save($data);

        return $result;
    }

    //添加交易记录
    private function addCapitalLog($order_sn, $master, $slave, $platformID, $log_type, $currency, $amount, $pre_trade, $order_time, $subject, $sid = null, $gid = null){
        $db = zyt_data_init();
        $data = [];
        $data['money_log_no'] = $order_sn;
        $data['money_log_master_user_id'] = $master;
        $data['money_log_slave_user_id']  = $slave;
        $data['money_log_platform_id']    = $platformID;
        $data['money_log_class']          = $log_type;
        $data['money_log_currency']       = $currency;
        $data['money_log_count']          = $amount;
        $data['money_log_pre_trade']      = $pre_trade;
        $data['money_log_time']           = $order_time;
        $data['money_log_desc']           = $subject;
        $db->table('money_log')->add($data);

        if( $gid > 0 && $sid > 0 ){ //如果是充值到游戏，则记录服务器ID和游戏ID
            $insertId = $db->getLastInsertId();
            $data = array();
            $data['log_money_id'] = $insertId;
            $data['log_addition_game_id'] = $gid;
            $data['log_addition_game_server_id'] = $sid;
            $db->table('money_log_additon')->add($data);
        }
    }
}